package gee

import (
	"html/template"
	"log"
	"net/http"
	"path"
	"strings"
)

//HandlerFunc defines the request handler by gee
type HandlerFunc func(*Context)

// 分组的功能，原本觉得这个功能没有必要，但是想了想，确实是刚需
type RouterGroup struct {
	prefix      string
	middlewares []HandlerFunc //support middlerware
	parent      *RouterGroup  //support nesting(嵌套)
	// 拥有engine字段是因为router是写在engine里的如果routergroup需要这个的话就可以通过engine去调用
	engine *Engine // all groups share a Engine instance
}

// Engine implement the interface of ServeHTTP
type Engine struct {
	*RouterGroup // 这个是Go的匿名嵌套结构体的写法嗷
	// Engine代表拥有全部的RouterGroup的成员
	router        *router
	groups        []*RouterGroup //store all groups
	htmlTemplates *template.Template
	funcMap       template.FuncMap
}

func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
	engine.funcMap = funcMap
}

func (engine *Engine) LoadHTMLGlob(pattern string) {
	engine.htmlTemplates = template.Must(template.New("").Funcs(engine.funcMap).ParseGlob(pattern))
}

//New is the constructor of gee.Engine
func New() *Engine {
	engine := &Engine{router: newRouter()}
	engine.RouterGroup = &RouterGroup{engine: engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
}

// RouterGroup到底是啥捏，其实就是一个分组器
// 为了就是将拥有相同前缀的url归类，这样的话每个组里面就会有自己的HandlerFunc，就不需要一个总体上定义自己的方法了
// 感觉目的是为了分组协作开发代码更为方便

func (group *RouterGroup) Group(prefix string) *RouterGroup {
	engine := group.engine
	newGroup := &RouterGroup{
		prefix: group.prefix + prefix, //为了支持组的见嵌套
		parent: group,
		engine: engine,
	}
	engine.groups = append(engine.groups, newGroup)
	return newGroup
}

func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) {
	pattern := group.prefix + comp
	log.Printf("Router %4s - %s\n", method, pattern)
	group.engine.router.addRoute(method, pattern, handler)
}

// GET defines the method to add GET request
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
	group.addRoute("GET", pattern, handler)
}

// POST defines the method to add POST request
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
	group.addRoute("POST", pattern, handler)
}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var middlerwares []HandlerFunc
	for _, group := range engine.groups {
		if strings.HasPrefix(req.URL.Path, group.prefix) {
			middlerwares = append(middlerwares, group.middlewares...)
		}
	}
	c := newContext(w, req)
	c.handlers = middlerwares
	c.engine = engine
	engine.router.handle(c)

}

// Default use Logger() & Recovery middlewares
func Default() *Engine {
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

// Run defines the method to start a http server
func (engine *Engine) Run(addr string) (err error) {
	return http.ListenAndServe(addr, engine)
}

// Use is defined to add middleware to the group
func (group *RouterGroup) Use(middleware ...HandlerFunc) {
	group.middlewares = append(group.middlewares, middleware...)
}

// create staic handler
func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
	absolutePath := path.Join(group.prefix, relativePath)
	fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
	return func(c *Context) {
		file := c.Param("filepath")
		if _, err := fs.Open(file); err != nil {
			c.Status(http.StatusNotFound)
			return
		}
		fileServer.ServeHTTP(c.Writer, c.Req)
	}
}

// Static serve static files
func (group *RouterGroup) Static(relativePath string, root string) {
	handler := group.createStaticHandler(relativePath, http.Dir(root))
	urlPattern := path.Join(relativePath, "/*filepath")
	// Register
	group.GET(urlPattern, handler)
}

// 说实话现在我有点点混乱...
// context也有HandlerFunc了，handlerfunc难道不是用来映射路由对应函数的嘛，现在貌似是一个通用的参数为req和r的函数定义而已
// context里的func应该是所谓的中间件函数
// engine里的handler的func应该是那种所有路由通用的函数， fuck这个框架感觉怎么不是很清晰的，是不是因为我对web框架理解不够
